package historymanager.tools;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

import org.apache.log4j.Logger;

/**
 * <p>
 * Class is used to compress data-series.
 * </p>
 * 
 * @author Thomas Aulich
 * @version 1.0
 *
 */
public class MeasureCompressor implements Runnable {
	static Logger log = Logger.getLogger(MeasureCompressor.class);
	private Configuration myConfig;

	public MeasureCompressor() {
		log.debug("Constuctor was called ...");
		myConfig = Configuration.getInstance();
	}

	@Override
	public void run() {
		log.debug("Run was called ...");
		Context envContext;
		try {
			log.debug("Try to establish database connection ...");
			envContext = new InitialContext();
			DataSource ds = (DataSource) envContext.lookup(myConfig
					.getDataSourceContext());
			Connection con = ds.getConnection();
			String SQLString = "";
			while (true) {
				// Looping around all measures which have not been processed
				Statement stmt1 = con.createStatement();
				SQLString = "select distinct measurepoint from measure where msid = 0 or msid = null";
				ResultSet rs1 = stmt1.executeQuery(SQLString);
				log.debug("Running check-cycle to see, what new measures have to be performed ...");
				while (rs1.next()) {
					long measurepoint = rs1.getLong("measurepoint");
					Statement stmt2 = con.createStatement();
					// Get last processed msid of this series (measurepoint)
					SQLString = "select max(msid) from measure where measurepoint = "
							+ String.valueOf(measurepoint);
					ResultSet rs2 = stmt2.executeQuery(SQLString);
					long msid = 0;
					if (rs2.next()) {
						msid = rs2.getLong(1);
					}
					// Get deviation from this measurepoint
					double deviation = 0.0;
					SQLString = "select deviation from measurepoint where id = " + measurepoint;
					rs2 = stmt2.executeQuery(SQLString);
					if (rs2.next()) {
						deviation = rs2.getDouble(1);
					}					
					// Now get historic data for compression (last record
					// values);
					double lastval = 0.0;
					long lastid = 0;
					double actval = 0.0;
					double calculatedDeviation = 0.0;
					long actid = 0;
					boolean isRelevant = false;
					SQLString = "select * from measure where measurepoint = "
							+ String.valueOf(measurepoint) + " and msid = " + 0;
					rs2 = stmt2.executeQuery(SQLString);
					if (rs2.next()) {
						lastid = rs2.getLong("id");
						lastval = rs2.getDouble("val");
					}
					rs2.close();
					SQLString = "select id, val from measure where measurepoint = "
							+ String.valueOf(measurepoint)
							+ " and msid = 0 or msid = null order by at";
					log.debug("Processing measurepoint "
							+ String.valueOf(measurepoint) + ", max till now: "
							+ String.valueOf(msid) + "; SQL:" + SQLString);
					rs2 = stmt2.executeQuery(SQLString);
					Statement stmt3 = con.createStatement();
					while (rs2.next()) {
						isRelevant = false;
						actid = rs2.getLong("id");
						actval = rs2.getDouble("val"); 
						msid++;
						// Update the actual record with the calculated 
						// measurepoint series id
						SQLString = "update measure set msid = "
								+ String.valueOf(msid) + " where id = "
								+ String.valueOf(actid);
						stmt3.execute(SQLString);
						// Check, if the last record is relevant or not
						// This depends from the measurepoints deviation
						if ((lastval != actval) && (lastval != 0)) {
							calculatedDeviation = Math.abs(1-(actval/lastval)); 
							if((calculatedDeviation) >= (Math.abs(deviation))) {
								isRelevant = true;	
							}
						}
						SQLString = "update measure set relevant = "
								+ String.valueOf(isRelevant) + " where id = "
								+ String.valueOf(lastid);
						stmt3.execute(SQLString);						
						lastid = actid;
						lastval = actval;
					}
					stmt3.close();
					rs2.close();
					stmt2.close();
				}
				log.debug("... check-cycle finished.");
				rs1.close();
				stmt1.close();
				try {
					log.debug("... thread sleeping for 10 minutes now ...");
					Thread.sleep(600000);
				} catch (InterruptedException e) {
					log.error("Exception occurred while pausing: "
							+ e.getMessage());
				}
			}
		} catch (NamingException e) {
			log.error("NamingException happened: " + e.getMessage());
			e.printStackTrace();
		} catch (SQLException e) {
			log.error("SQLException happened: " + e.getMessage());
		}

		log.debug("Run is finishing ...");
	}
}
